// gameserver.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "gameserver.h"
#include <fgeTimePlugin.h>
#include <fgeCmdInterface.h>
#include <DbgHelp.h>
#pragma comment(lib, "DbgHelp.lib")

using namespace fge;
using namespace ocl;
using namespace protocol;

bool InitError(char* ErrorInfo);
LONG WINAPI TopLevelFilter( _EXCEPTION_POINTERS *pExceptionInfo );

TcpServer* Net::s_pNetGameServer = 0;
TcpClient* Net::s_pNetDB = 0;
int _tmain(int argc, _TCHAR* argv[])
{
	#ifdef _BUFFER_OVERFLLOW	
	#if defined(WIN32) && defined(_DEBUG) 
		int tmpDbgFlag;
	
		tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
		tmpDbgFlag |= _CRTDBG_DELAY_FREE_MEM_DF;
		tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
		_CrtSetDbgFlag(tmpDbgFlag);
	#endif //WIN32 & _DEBUG
	#endif	
	srand(timeGetTime());
	Random_Seed(timeGetTime());

	SetUnhandledExceptionFilter( TopLevelFilter );

	Net::s_pNetGameServer = new TcpServer();
	Net::s_pNetDB = new TcpClient();

	ocl::TcpServer* pTcpServer	= Net::s_pNetGameServer;
	//ocl::TcpClient* pDBClient	= Net::s_pNetDB;

	CDBServer* pDBServer	= INSTANCE(CDBServer);
	CGameServer* pGameServer	= INSTANCE(CGameServer);

	pDBServer->Start();
	pGameServer->Start();

	gameWorld::CNpc npc;
	npc.Init();
	fge::CXML xmlServer;
	try
	{
		if(!xmlServer.Open("../server.xml"))
			throw std::exception("can not open file server.xml");
		fge::Element* pelement = xmlServer.FindElement("game_server");
		if( !pelement )
			throw std::exception("can not find game_server configer in file server.xml");
		std::string strIp="127.0.0.1";
		int nPort=9800;

		pelement->GetAttribute("ip",strIp);
		pelement->GetAttribute("port",nPort);

		pTcpServer->AddListener(new CNetMsgListener());
		pTcpServer->Open(strIp.c_str(),nPort,0);

		//pelement = xmlServer.FindElement("db_server");
		//if( !pelement )
		//	throw fge::XMLException("can not find db_server configer in file server.xml");
		//strIp="127.0.0.1";
		//nPort=9801;
		//pelement->GetAttribute("ip",strIp);
		//pelement->GetAttribute("port",nPort);

		//if(pDBClient->Open(strIp.c_str(),nPort)<0)
		//	throw std::exception("can not connect to db_server");
	}
	catch (const std::exception& e)
	{
		std::cout<<e.what()<<std::endl;
		CLog::Write(e.what());
		return -1;
	}

	CCmdInterface cmd;
	cmd.Run();
	
	pDBServer->Close();
	pGameServer->Close();
	pTcpServer->Close();
	//pDBClient->Close();

	SAFE_DELETE(Net::s_pNetGameServer);
	SAFE_DELETE(Net::s_pNetDB);
	return 0;
}



bool InitError(char* ErrorInfo)
{
	INSTANCE(CLog)->Log(LEVEL_ALERT,"Init %s Error! Press [Enter] key exit CGameServer!!!(See ErrorDoc!)",ErrorInfo);
	getchar();
	return false;
}
LONG WINAPI TopLevelFilter( _EXCEPTION_POINTERS *pExceptionInfo )
{
	LONG ret = EXCEPTION_CONTINUE_SEARCH;

	time_t  nowtime;
	time(&nowtime);
	struct tm *pTime = localtime(&nowtime);
	char szFile[128] = {0};
	sprintf(szFile, "GameServer_%4d.%02d.%02d_%02d.%02d.%02d.dmp", pTime->tm_year+1900, pTime->tm_mon+1, pTime->tm_mday, pTime->tm_hour, pTime->tm_min, pTime->tm_sec);

	HANDLE hFile = ::CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hFile != INVALID_HANDLE_VALUE)
	{
		MINIDUMP_EXCEPTION_INFORMATION ExInfo;

		ExInfo.ThreadId = ::GetCurrentThreadId();
		ExInfo.ExceptionPointers = pExceptionInfo;
		ExInfo.ClientPointers = NULL;

		// write the dump
		BOOL bOK = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL );
		ret = EXCEPTION_EXECUTE_HANDLER;
		::CloseHandle(hFile);
	}
	return ret;
}

u_long	WINAPI SendToClient( const void* body, u_long size, ConnectionID id)
{
	return Net::s_pNetGameServer->Send((const char*)body,size,id);
}
u_long	WINAPI SendToClient( u_long msgid, const void* body, u_long size, ConnectionID id)
{
	protocol::NetMsg head;
	head.msg_id = msgid;
	head.msg_len = size;
	head.msg_num = 1;
	ocl::Packer	msg;
	msg.AddToBuf(&head,sizeof(head));
	msg.AddToBuf(body,size);
	return SendToClient(msg(),msg.GetBufferLen(),id);
}
u_long	WINAPI SendToDB( const void* body, u_long size )
{
	//CMessageManager* pMsgQueue = INSTANCE(CGameServer)->GetMessageQueue();
	NetMsg *pMsg = (NetMsg*)body;
	INSTANCE(CDBServer)->Push(pMsg->msg_id,(BYTE*)pMsg,sizeof(NetMsg),(BYTE*)pMsg+sizeof(NetMsg),size-sizeof(NetMsg));
	//return Net::s_pNetDB->Send(body,size);
	return size;
}
u_long	WINAPI SendToDB( u_long msgid, const void* body, u_long size)
{
	protocol::NetMsg head;
	head.msg_id = msgid;
	head.msg_len = size;
	head.msg_num = 1;
	ocl::Packer	msg;
	msg.AddToBuf(&head,sizeof(head));
	msg.AddToBuf(body,size);
	return SendToDB(msg(),msg.GetBufferLen());
}
u_long	WINAPI	SendToGS( u_long msgid, const void* body, u_long size )
{
	protocol::NetMsg head;
	head.msg_id = msgid;
	head.msg_len = size;
	head.msg_num = 1;

	INSTANCE(CGameServer)->Push(msgid,(BYTE*)&head,sizeof(NetMsg),(BYTE*)body,size);
	//return Net::s_pNetDB->Send(body,size);
	return size;
}
/************************************************************************/
/*                       CNetMsgListener                                */
/************************************************************************/
void	CNetMsgListener::OnAccept( const char* ip, int port, ConnectionID id )
{
	printf("[%d]%s:%d connected\n",id.nID,ip,port);
}
void	CNetMsgListener::OnDisconnect( ConnectionID id )
{
	printf("[%d] disconnected\n",id.nID);
}
void	CNetMsgListener::OnRecv( const char* body, u_long size, ConnectionID id )
{
	if( size<=0 )
		return;
	CMessageManager* pMsgQueue = INSTANCE(CGameServer)->GetMessageQueue();
	NetMsg *pMsg = (NetMsg*)body;
	ServerMsgHead head;
	head.client_id = id.nID;
	head.client_sync_id = id.nSyncID;
	head.msg_num = pMsg->msg_num;
	if(pMsg->msg_len <= size)
		pMsgQueue->Push(pMsg->msg_id,(BYTE*)&head,sizeof(ServerMsgHead),(BYTE*)pMsg+sizeof(NetMsg),size-sizeof(NetMsg));
}
/************************************************************************/
/*                         CGameServer                                  */
/************************************************************************/
CGameServer::CGameServer(void)
{
}

CGameServer::~CGameServer(void)
{
}
void	CGameServer::OnInstall()
{
	CActiveService::OnInstall();
	InstallPlugin( INSTANCE(fge::CTimePlugin) );
	InstallPlugin( INSTANCE(gameWorld::CPlayerManager) );
}
void	CGameServer::OnUninstall()
{
	CActiveService::OnUninstall();
}
